package org.dragonnova.meetingserver.server.service;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcelable;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;

import org.dragonnova.meetingserver.R;
import org.dragonnova.meetingserver.core.SocketUtils;
import org.dragonnova.meetingserver.core.manager.NetManager;
import org.dragonnova.meetingserver.core.manager.NettyManager;
import org.dragonnova.meetingserver.core.manager.UdpManager;
import org.dragonnova.meetingserver.utils.LogUtil;
import org.dragonnova.meetingserver.utils.PromptUtil;
import org.dragonnova.meetingserver.utils.WifiAutoConnectUtil;

import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.List;

/**
 * @author songxy
 *         Created at 2015/12/7 10:36
 *         Email: thinkdata@163.com
 *         用于管理WIFI网络入口、服务端通信、数据传输
 */
public class WIFIServiceTest extends Service {

    private final static String TAG = WIFIServiceTest.class.getName();

    /**
     * 当前的网络状态
     */
    public final static int NET_DISABLED_STATUS = 0;
    public final static int NET_WIFI_STATUS = 1;
    public final static int NET_ETHERNET_STATUS = 2;
    public final static int NET_MOBILE_STATUS = 3;
    /**
     * UDP服务端IP
     */
    public static String UDP_SERVER_IP;
    /**
     * 本地网络状态
     */
    private int mCurrentNetStatus = NET_DISABLED_STATUS;
    /**
     * ping网络的线程
     */
    public NetPingThread netPingWorker;
    // wifi、网络管理器
    private WifiManager mWifiManager;
    private ConnectivityManager mConnectivityManager;
    // binder
    private ServiceBinder serviceBinder;
    // 网络状态广播接收
    private NetGroupReceiver mNetReceiver;
    // 组网管理和发送信息的管理
    private NetManager mNetManager;
    // 测试，固定ip
    private static String UNIQUE_SSID = "G105-9";
    private static String UNIQUE_PASSWORD = "11111111";
    /*private String UNIQUE_SSID = "development";
    private String UNIQUE_PASSWORD = "12345678";*/
    //网络的不同状态
    private StateImp mState;
    private EthernetState mEthernetState;
    private WifiState mWifiState;
    private DefaultStatus mDefaultState;
    //开启WIFI的功能类
    private WifiAutoConnectUtil mWifiAutoConnectUtil;

    @Override
    public void onCreate() {
        super.onCreate();
        //注册广播
        registerNetReceiver();
        //初始化参数
        initParam();
        // checkWifi();
        // 启动网络线程，组网、服务SOCKET初始化
        initNetManager();
        startNetPing();
    }

    /**
     * 初始化变量
     */
    private void initParam() {
        // 初始化网络状态对象
        mEthernetState = new EthernetState();
        mWifiState = new WifiState();
        mState = mEthernetState;
        // 初始化WIFI相管理器
        mWifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
        // 开启WIFI的功能类
        mWifiAutoConnectUtil = new WifiAutoConnectUtil(mWifiManager);
        // 初始化网络管理
        mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    }

    /**
     * 添加WIFI,网络活动状态下才能建立组网和UDP线程
     * 固定ip，自动组网
     */
    private void checkWifi() {
        //拿到网络状态，进行判断
        //[type: WIFI[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: "G105-2", roaming: false, failover: false, isAvailable: true, isConnectedToProvisioningNetwork: false]
        NetworkInfo networkInfo = mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        //SSID: G105-2, BSSID: 30:fc:68:69:a1:04, MAC: cc:a2:23:36:10:a8, Supplicant state: COMPLETED, RSSI: -24, Link speed: 72Mbps, Frequency: 2462MHz, Net ID: 8, Metered hint: false, score: 100
        WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
        //wifi是否未连接，数据服务要等到连接以后才能进行
        if ((networkInfo.getState() == NetworkInfo.State.CONNECTED) && wifiInfo.getSSID() != null && (wifiInfo.getSSID().equalsIgnoreCase("\"" + UNIQUE_SSID + "\"") || wifiInfo.getSSID().equalsIgnoreCase(UNIQUE_SSID))) {
            //192.168.1.100
            UDP_SERVER_IP = SocketUtils.convertIntIpAddress(getWifiInfo().getIpAddress());
        } else {
            doWifiRefresh(UNIQUE_SSID, UNIQUE_PASSWORD, "WAP");
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return Service.START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        try {
            unregisterReceiver(mNetReceiver);
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "onDestroy Error: " + e.getMessage());
        }
        mNetManager.stop();
        mNetManager.destory();
        mNetManager = null;
        stopNetPing();
    }

    /**
     * 销毁除了主线程和网络监听线程外的其他线程
     */
    private void stopNetPing() {
        if (netPingWorker != null) {
            netPingWorker.setFlag(false);
            netPingWorker = null;
        }
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i(TAG, "WIFIService unBind");
        serviceBinder = null;
        return false;
    }

    public IBinder onBind(Intent intent) {
        Log.i(TAG, "WIFIService onBind");
        serviceBinder = new ServiceBinder();
        return serviceBinder;
    }

    /**
     * 刷新网络
     */
    private void doWifiRefresh(final String ssid, final String passwd, final String wifiKey) {
        if (TextUtils.equals(wifiKey, "WAP")) {
            mWifiAutoConnectUtil.connect(ssid, passwd, WifiAutoConnectUtil.WifiCipherType.WIFICIPHER_WPA);
        }
    }

    /**
     * 注册广播
     */
    private void registerNetReceiver() {
        mNetReceiver = new NetGroupReceiver();
        registerReceiver(mNetReceiver, getFilter());
    }

    /**
     * 开启网络管理类
     */
    private void initNetManager() {
        mNetManager = new UdpManager(WIFIServiceTest.this, mWifiManager);
        //mNetManager.start();
    }

    private void startNetPing() {
        netPingWorker = new NetPingThread();
        netPingWorker.start();
    }

    private IntentFilter getFilter() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
        filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        return filter;
    }

    private WifiInfo getWifiInfo() {
        return mWifiManager.getConnectionInfo();
    }


    public class ServiceBinder extends Binder {
        public WIFIServiceTest getService() {
            return WIFIServiceTest.this;
        }
    }

    private class NetPingThread extends Thread {
        private boolean waitFlag = true;
        private int disconnectedCount = 0;
        private int connectedCount = 0;

        @Override
        public void run() {
            // 联网且是WIFI网络状态下
            while (waitFlag) {
                Runtime run = Runtime.getRuntime();
                Process proc = null;
                try {
                    String str = "ping -c 1 -i 0.2 -W 1 " + "202.108.22.5";
                    System.out.println(str);
                    proc = run.exec(str);
                    int result = proc.waitFor();
                    if (result == 0) {
                        LogUtil.eee("Ping successfully");
                        if (connectedCount == 0)
                            PromptUtil.poolPlay(WIFIServiceTest.this, R.raw.internet_connected);
                        connectedCount++;
                        disconnectedCount = 0;
                    } else {
                        LogUtil.eee("Ping fail");
                        if (disconnectedCount == 5) {
                            PromptUtil.poolPlay(WIFIServiceTest.this, R.raw.internet_disconnected);
                            connectedCount = 0;
                        }
                        disconnectedCount++;
                    }
                } catch (IOException | InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    if (proc != null) proc.destroy();
                }
                SystemClock.sleep(5000);
            }
        }

        public void setFlag(boolean flag) {
            this.waitFlag = flag;
        }
    }

    /**
     * 网络的全局广播
     */
    private class NetGroupReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
            WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
            if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
                //进入应用首先会检查网络状况
                if (networkInfo != null && networkInfo.isConnected()) {
                    ///网络连接
                    if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                        //wifi连接
                        LogUtil.eee("NET_TYPE_WIFI_CONNECTED");
                        mCurrentNetStatus = NET_WIFI_STATUS;
                        mState = mWifiState;
                    } else if (networkInfo.getType() == ConnectivityManager.TYPE_ETHERNET) {
                        //有线网络
                        LogUtil.eee("NET_TYPE_ETHERNET_CONNECTED");
                        mCurrentNetStatus = NET_ETHERNET_STATUS;
                        mState = mEthernetState;
                        try {
                            String ethernetIp = null;
                            for (Enumeration<NetworkInterface> en = NetworkInterface
                                    .getNetworkInterfaces(); en.hasMoreElements(); ) {
                                NetworkInterface intf = en.nextElement();
                                for (Enumeration<InetAddress> enumIpAddr = intf
                                        .getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
                                    InetAddress inetAddress = enumIpAddr.nextElement();
                                    if (!inetAddress.isLoopbackAddress()) {
                                        ethernetIp = inetAddress.getHostAddress();
                                        LogUtil.ddd("ethernetIp = " + ethernetIp);
                                    }
                                }
                            }
                            if (ethernetIp != null && !ethernetIp.equals(UDP_SERVER_IP)) {
                                UDP_SERVER_IP = ethernetIp;
                            }
                            mState.correct();
                        } catch (SocketException ex) {
                            ex.printStackTrace();
                        }
                    } else if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
                        //3g网络
                        LogUtil.eee("NET_TYPE_MOBILE_CONNECTED");
                        mCurrentNetStatus = NET_MOBILE_STATUS;
                        mState = mDefaultState;
                    }
                } else if (networkInfo != null && networkInfo.isAvailable()) {
                    //有网络，但是没有连接
                    LogUtil.eee("NET_TYPE_AVAILABLE");
                    ///网络连接
                    if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                        //wifi连接
                        LogUtil.eee("NET_TYPE_WIFI_DISCONNECTED");
                        mCurrentNetStatus = NET_WIFI_STATUS;
                        mState = mWifiState;

                    } else if (networkInfo.getType() == ConnectivityManager.TYPE_ETHERNET) {
                        //有线网络
                        LogUtil.eee("NET_TYPE_ETHERNET_DISCONNECTED");
                        mCurrentNetStatus = NET_ETHERNET_STATUS;
                        mState = mEthernetState;

                    } else if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
                        //3g网络
                        LogUtil.eee("NET_TYPE_MOBILE_DISCONNECTED");
                        mCurrentNetStatus = NET_MOBILE_STATUS;
                        mState = mDefaultState;
                    }
                } else {
                    //其他状态
                    LogUtil.eee("NET_TYPE_NOT_AVAILABLE");
                    //如果没有网络，那么默认为有线
                    mCurrentNetStatus = NET_DISABLED_STATUS;
                    // mState = mWifiState;
                    // mWifiState.disabled();
                    mState.disabled();
                    //checkWifi();
                }
            } else if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
                int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
                switch (wifiState) {
                    case WifiManager.WIFI_STATE_DISABLED:
                        LogUtil.e("WifiState", "DISABLED");
                        mState.disabled();
                        break;
                    case WifiManager.WIFI_STATE_DISABLING:
                        break;
                    case WifiManager.WIFI_STATE_ENABLED:
                        LogUtil.e("WifiState", "ENABLED");
                        if (mCurrentNetStatus == NET_DISABLED_STATUS) {
                            mCurrentNetStatus = NET_WIFI_STATUS;
                            mState.enabled();
                        }
                        break;
                    case WifiManager.WIFI_STATE_ENABLING:
                        break;
                    case WifiManager.WIFI_STATE_UNKNOWN:
                        break;
                }
            } else if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
                Parcelable parcelableExtra = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
                if (null != parcelableExtra) {
                    NetworkInfo info = (NetworkInfo) parcelableExtra;
                    switch (info.getState()) {
                        case CONNECTED:
                            // 网络已连接
                            LogUtil.e("WifiState", "CONNECTED");
                            mState.connected();
                            if (wifiInfo.getSSID() != null && (wifiInfo.getSSID().equalsIgnoreCase("\"" + UNIQUE_SSID + "\"") || wifiInfo.getSSID().equalsIgnoreCase(UNIQUE_SSID))) {
                                LogUtil.e("WifiState", "CORRECT");
                                String currentIp = SocketUtils.convertIntIpAddress(wifiInfo.getIpAddress());
                                if (currentIp != null && !currentIp.equals(UDP_SERVER_IP)) {
                                    UDP_SERVER_IP = currentIp;
                                }
                                mState.correct();
                            } else {
                                //连接的不是制定的网络
                                LogUtil.e("WifiState", "INCORRECT");
                                mState.incorrect();
                            }
                            break;
                        case CONNECTING:
                            LogUtil.e("WifiState", "CONNECTING");
                            break;
                        case DISCONNECTED:
                            LogUtil.e("WifiState", "DISCONNECTED");
                            mState.disconnected();
                            break;
                        case DISCONNECTING:
                            LogUtil.e("WifiState", "DISCONNECTING");
                            break;
                        case SUSPENDED:
                            LogUtil.e("WifiState", "SUSPENDED");
                            break;
                        case UNKNOWN:
                            LogUtil.e("WifiState", "UNKNOWN");
                            break;
                        default:
                            break;
                    }
                }
            } else if (intent.getAction().equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
                Boolean state = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false);
                Log.d(TAG, "NetworkInfo connected Statue: " + state);
            } else if (intent.getAction().equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) {
                SupplicantState state = intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE);
                Log.d(TAG, "NetworkInfo connected Statue: " + state);
            } else if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
                List<ScanResult> results = mWifiManager.getScanResults();
                for (ScanResult result : results) {
                    Log.d(TAG, "SCAN_RESULTS_AVAILABLE_ACTION " + "BSSID: " + result.BSSID
                            + ", SSID: " + result.SSID);
                }
            }
        }
    }

    /**
     * 网络状态变更的实现
     */
    private class WifiState implements StateImp {

        private NetStatus preNetStatus = NetStatus.UNKNOWN_STATUS;
        private NetStatus netStatus = NetStatus.UNKNOWN_STATUS;

        @Override
        public void disabled() {
            preNetStatus = netStatus;
            netStatus = NetStatus.DISABLED_STATUS;
            if (preNetStatus != netStatus) {
                mNetManager.stop();
                checkWifi();
            }
        }

        @Override
        public void enabled() {
            netStatus = NetStatus.ENABLED_STATUS;
        }

        @Override
        public void connecting() {
            netStatus = NetStatus.CONNECTING_STATUS;
        }

        @Override
        public void connected() {
            netStatus = NetStatus.CONNECTED_STATUS;
        }

        @Override
        public void disconnected() {
            preNetStatus = netStatus;
            netStatus = NetStatus.DISCONNECTED_STATUS;
            if (preNetStatus != netStatus) {
                mNetManager.stop();
                checkWifi();
            }
        }

        @Override
        public void incorrect() {
            preNetStatus = netStatus;
            netStatus = NetStatus.INCORRECT_STATUS;
            if (preNetStatus != netStatus) {
                mNetManager.stop();
                checkWifi();
            }
        }

        @Override
        public void correct() {
            preNetStatus = netStatus;
            netStatus = NetStatus.CORRECT_STATUS;
            if (preNetStatus != netStatus) {
                mNetManager.setServerIp(UDP_SERVER_IP);
                if (!mNetManager.isStarted()) {
                    mNetManager.start();
                }
            }
        }

        @Override
        public NetStatus getStatus() {
            return netStatus;
        }
    }

    /**
     * 网络状态变更的实现
     */
    private class EthernetState implements StateImp {

        private NetStatus preNetStatus = NetStatus.UNKNOWN_STATUS;
        private NetStatus netStatus = NetStatus.UNKNOWN_STATUS;

        @Override
        public void disabled() {
            preNetStatus = netStatus;
            netStatus = NetStatus.DISABLED_STATUS;
            if (preNetStatus != netStatus) {
                mNetManager.stop();
                //checkWifi();
            }
        }

        @Override
        public void enabled() {
            netStatus = NetStatus.ENABLED_STATUS;
        }

        @Override
        public void connecting() {
            netStatus = NetStatus.CONNECTING_STATUS;
        }

        @Override
        public void connected() {
            netStatus = NetStatus.CONNECTED_STATUS;
        }

        @Override
        public void disconnected() {
            preNetStatus = netStatus;
            netStatus = NetStatus.DISCONNECTED_STATUS;
            if (preNetStatus != netStatus) {
                mNetManager.stop();
                //checkWifi();
            }
        }

        @Override
        public void incorrect() {
            preNetStatus = netStatus;
            netStatus = NetStatus.INCORRECT_STATUS;
            if (preNetStatus != netStatus) {
                mNetManager.stop();
                //checkWifi();
            }
        }

        @Override
        public void correct() {
            preNetStatus = netStatus;
            netStatus = NetStatus.CORRECT_STATUS;
            if (preNetStatus != netStatus) {
                mNetManager.setServerIp(UDP_SERVER_IP);
                if (!mNetManager.isStarted()) {
                    mNetManager.start();
                }
            }
        }

        @Override
        public NetStatus getStatus() {
            return netStatus;
        }
    }

    private class DefaultStatus implements StateImp {

        @Override
        public void disabled() {

        }

        @Override
        public void enabled() {

        }

        @Override
        public void connecting() {

        }

        @Override
        public void connected() {

        }

        @Override
        public void disconnected() {

        }

        @Override
        public void incorrect() {

        }

        @Override
        public void correct() {

        }

        @Override
        public NetStatus getStatus() {
            return null;
        }
    }

    /**
     * 网络状态变更的接口
     */
    private interface StateImp {
        /**
         * 用于组网状态标识：未开启，开启，连接中，已连接，未连接，连接到正确的网络，连接到不正确的网络
         */
        enum NetStatus {
            UNKNOWN_STATUS, DISABLED_STATUS, ENABLED_STATUS,
            CONNECTING_STATUS, CONNECTED_STATUS, DISCONNECTED_STATUS,
            INCORRECT_STATUS, CORRECT_STATUS
        }

        void disabled();

        void enabled();

        void connecting();

        void connected();

        void disconnected();

        void incorrect();

        void correct();

        NetStatus getStatus();
    }
}
